package controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Item;
import model.Sale;
import model.ShoppingBasket;
import model.XML;
import model.environment.Items;
import model.environment.Login;
import model.environment.StaticInfo;

import org.jdom.Document;

public class Controller extends HttpServlet {
	private static final long serialVersionUID = -2670825831853246200L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String command = request.getServletPath();
		
		if (command.equals("/addToBasket.do")) {
			Map<String, String> getData = StaticInfo.getGetData(request);
			
			try {
				int itemID = Integer.parseInt(getData.get("itemID"));
				
				String amountStr = getData.get("amount");
				
				// "amount" is optional, default is 1.
				if (amountStr == null) {
					amountStr = "1";
				}
				
				int amount = Integer.parseInt(amountStr);
				
				ShoppingBasket.getShoppingBasket(request.getSession()).add(itemID, amount);
			} catch (NumberFormatException e) {
				
			}
			
			response.sendRedirect("basket.jsp");
			return;
		} else if (command.equals("/checkout.do")) {
			String checkoutURL = "http://services.brics.dk/java4/cloud/sellItems";
			
			int customerID = Login.getLoginID(request.getSession());
			
			if (customerID == 0 || customerID == -1) {
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.LOGIN_FAILED);
				response.sendRedirect("basket.jsp");
				return;
			}
			
			ShoppingBasket basket = ShoppingBasket.getShoppingBasket(request.getSession());
			int origSize = basket.getItemsInBasket();
			HashMap<Integer, Integer> basketMap = basket.getHashMap();
			
			// Assume that things will be okay.
			request.getSession().setAttribute("pviMessage", StaticInfo.Message.CHECKOUT_OK);
			
			for (Map.Entry<Integer, Integer> entry : basketMap.entrySet()) {
				int itemID = entry.getKey();
				int amount = entry.getValue();
				
				Sale newSale = new Sale(amount, itemID, customerID);
				Document d = XML.createSellItemsElement(newSale, StaticInfo.SHOP_KEY);
				
				Document xmlResponse;
				try {
					xmlResponse = XML.postXML(d, checkoutURL);

					if (XML.checkoutItemSuccessfull(xmlResponse)) {
						basket.set(itemID, 0);
					}
				} catch (Exception e) {
					// Something went wrong, don't remove the item from the basket.
				}
			}
			
			if (basket.getItemsInBasket() == origSize) {
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.CHECKOUT_FAILED);	
			} else if (basket.getItemsInBasket() > 0) {
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.CHECKOUT_MIXED);
			}
			
			// Force update of item list now that the stock of items has changed.
			Items.resetItemsList();
			
			response.sendRedirect("confirm.jsp");
			return;
		} else if (command.equals("/logout.do")) {
			Login.logout(request.getSession());
			
			String redirect = request.getHeader("referer");
			response.sendRedirect(redirect);
		} else {
			response.sendRedirect("frontpage.jsp");
			return;
		}
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String command = request.getServletPath();
		if (command.equals("/updateBasket.do")) {
			Map<String, String> postData = StaticInfo.getPostData(request);
			
			for (Map.Entry<String, String> entry : postData.entrySet()) {
				try {
					int id = Integer.parseInt(entry.getKey());
					int amount;
					if (entry.getValue().equals(""))
						amount = 0;
					else
						amount = Integer.parseInt(entry.getValue());
					
					Item item = Items.getItem(id);
					int stock = item.getItemStock();
					
					// We can not set the amount higher than the item stock.
					if (amount > stock)
						amount = stock;
					
					ShoppingBasket.getShoppingBasket(request.getSession()).set(id, amount);
				} catch (NumberFormatException e) {
					continue;
				}
			}
			
			String redirect = request.getHeader("referer");
			response.sendRedirect(redirect);
			return;
		} else if (command.equals("/login.do")) {
			Map<String, String> postData = StaticInfo.getPostData(request);
			
			String username = postData.get("username");
			String password = postData.get("password");
			
			if (Login.doLogin(username, password, request.getSession())) {
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.LOGIN_OK);
			} else {
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.LOGIN_FAILED);
			}
			
			String redirect = request.getHeader("referer");
			response.sendRedirect(redirect);
		} else if (command.equals("/createUser.do")) {
			Map<String, String> postData = StaticInfo.getPostData(request);
			
			String username = postData.get("username");
			String password = postData.get("password");
			String password2 = postData.get("password2");
			
			// Check to see if the two passwords match.
			if (password.equals(password2)) {
				// Passwords match, attempt to create user.
				if (Login.createUser(username, password)) {
					request.getSession().setAttribute("pviMessage", StaticInfo.Message.CREATEUSER_OK);
					
					// User created. Attempt to login.
					if (!Login.doLogin(username, password, request.getSession())) {
						request.getSession().setAttribute("pviMessage", StaticInfo.Message.LOGIN_FAILED);
					}
				} else {
					request.getSession().setAttribute("pviMessage", StaticInfo.Message.CREATEUSER_FAILED);
				}
			} else {
				// The two passwords do not match.
				request.getSession().setAttribute("pviMessage", StaticInfo.Message.CREATEUSER_FAILED);
			}
			
			String redirect = request.getHeader("referer");
			response.sendRedirect(redirect);
			return;
		} else if (command.equals("/editItem.do")) {
			if (!Login.isAdministrator(request.getSession()))
			{
				response.sendError(403);
				return;
			}
		
			Map<String, String> postData = StaticInfo.getPostData(request);
			
			int itemID;
			
			try {
				itemID = Integer.parseInt(postData.get("id"));
			} catch (NumberFormatException e) {
				itemID = -1;
			}
						
			String itemName = postData.get("name");
			
			int newStock;
			try {
				newStock = Integer.parseInt(postData.get("stock"));
			} catch (NumberFormatException e) {
				newStock = 0;
			}
			
			int itemPrice;
			try {
				itemPrice = Integer.parseInt(postData.get("price"));
			} catch (NumberFormatException e) {
				itemPrice = 0;
			}
			
			String itemURL = postData.get("url");
			
			String itemDescription = postData.get("description");
			// Replacing <ol> with <li> (because!)
			itemDescription = itemDescription.replaceAll("<ol>", "<ul>").replaceAll("</ol>", "</ul>");
			// Removing all tags, except <span>, <li>, <ul>, <b> and <i>.
			String itemDescriptionCleaned = itemDescription.replaceAll("<(?!(?:b|/b|span|/span|ul|/ul|li|/li|i|/i)\\b).*?>", "");
			StaticInfo.Message validateStatus = null;
			if (!itemDescriptionCleaned.equals(itemDescription))
			{
				validateStatus = StaticInfo.Message.VALIDATE_ITEM_DESCRIPTION_FAILED;
			}
			itemDescription = itemDescriptionCleaned;
			
			Item item = new Item(itemID, itemName, itemURL, itemPrice, newStock, itemDescription);
			
			StaticInfo.Message status = Items.modifyItem(item);

			// In case we have created a new item, we have to redirect to this new item.
			String redirect = "admin/editItem.jsp?itemID=" + item.getItemID();
			
			if (status == StaticInfo.Message.CREATE_ITEM_FAILED) {
				// In case we couldn't create a new item, send the user back to where they came from,
				// most likely "editItem.jsp" (without "?itemID=xxx").
				redirect = request.getHeader("referer");
			}
			
			// Appending the validateStatus we found before.
			if (validateStatus != null)
				status = validateStatus;
			
			// Force update of item list now that items have changed.
			Items.resetItemsList();

			request.getSession().setAttribute("pviMessage", status);
			response.sendRedirect(redirect);
			return;
		} else {
			doGet(request, response);
		}
	}
}
